﻿///////////////////////////////////////////////////////////////////////////////
// File Name: Skin.cpp 
// Purpose: Skin.h 实现文件
// Author: 张东斌、ChongyangLee
// E_Mail: malutianshi7905@sina.com; ChongyangLee@hotmail.com
// History: 
// 2009/09/25 Fix 根据 按钮皮肤名 加载 按钮皮肤
// 2009/09/25 Add 根据 ID 加载按钮皮肤
// 2009/10/11 Add 获得一个新的合法的 SkinName
// 
///////////////////////////////////////////////////////////////////////////////


#include "stdafx.h"
#include "skin.h"
#include "WindowSkin.h"
#include "ButtonSkin.h"
#include "ScrollBarSkin.h"
#include "StaticSkin.h"
#include "ButtonSkin.h"
#include "RadioSkin.h"
#include "CheckBoxSkin.h"
#include "GroupBoxSkin.h"
#include "EditSkin.h"
#include "ComboBoxSkin.h"
#include "ListBoxSkin.h"
#include "PopupMenuSkin.h"
#include "ProgressSkin.h"
#include "SpinSkin.h"
#include "HeaderSkin.h"
#include "SlideSkin.h"
#include "TabSkin.h"
#include "StatusbarSkin.h"
#include "ToolBarSkin.h"

#include <sstream>
#include <algorithm>

using namespace std;

///////////////////////////////////////////////////////
#define SKIN_IMAGE_MARK 22;
#define SKIN_OBJECT_MARK 33;

CSkin& GetSkin()
{
    static CSkin theSkin;
	return theSkin;
}
CSkinImages* GetImages()
{
	return GetSkin().GetImages();
}
CSkinBitmap* GetImage(const CString&  in_strName)
{
	return GetImages()->FindImage(in_strName);
}
//IMPLEMENT_SERIAL(CSkin,CObject,1)
CSkin::CSkin(void)
:m_pImages(NULL)
{
	m_pImages = new CSkinImages();
	m_nSkinVersion = 01;


}
CSkin::~CSkin(void)
{
	if(m_pImages)
		delete m_pImages;

	ClearSkin();
}

void CSkin::ClearSkin()
{
	for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
		iter != m_lstSkinObjects.end(); ++iter)
	{
		CObjectSkin* pObject = *iter;
		delete pObject;
	}

	m_lstSkinObjects.clear();
}
void CSkin::LoadSkin( const CString& strSkinFile )
{
    ClearSkin();

    CFile			cFile;
    CFileException	e;

    if (cFile.Open(strSkinFile, CFile::modeRead | CFile::typeBinary, &e))
    {
        LoadSkinInternal(&cFile);
        cFile.Close();
    }
}

void CSkin::LoadSkin( HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType )
{
    ClearSkin();
    HRSRC hr = FindResource(hModule, lpName, lpType);
    if (0 == hr){ return;}

    DWORD dwSize = SizeofResource( NULL, hr );
    if (0 == dwSize){ return;}

    HGLOBAL hg = LoadResource(hModule, hr);
    if (0 == hg){ return;}

    LPVOID  pr = LockResource(hg);
    if (0 == pr){ return;}

    CMemFile file;
    file.Attach(reinterpret_cast<BYTE*>(pr), dwSize);
    LoadSkinInternal(&file);
    file.Detach();
    UnlockResource(pr);
}

void CSkin::LoadSkinInternal( CFile* pFile)
{
    CArchive ar(pFile,CArchive::load);
    ar.Read(&m_nSkinVersion,sizeof(m_nSkinVersion));
    int imageMark;
    ar.Read(&imageMark,sizeof(imageMark));
    if(!m_pImages)
        m_pImages = new CSkinImages;
    m_pImages->Serialize(ar);

    ar.Read(&m_Application,sizeof(m_Application));
    int nObjectSkin = 0;
    ar.Read(&nObjectSkin,sizeof(nObjectSkin));
    for(int i = 0 ;i < nObjectSkin ; i++)
    {
        CObjectSkin *pObject = NULL;
        int nType = keUnknowSkin;
        ar.Read(&nType,sizeof(nType));

        if(nType == keWindowSkin)
        {
            pObject = new CWindowSkin;
        }
        else if(nType == keButtonSkin)
        {
            pObject = new CButtonSkin;
        }
        else if(nType == keScrollBarSkin)
        {
            pObject = new CScrollBarSkin;
        }
        else if(nType == keRadioSkin)
        {
            pObject = new CRadioSkin;
        }
        else if(nType == keCheckBoxSkin)
        {
            pObject = new CCheckBoxSkin;
        }
        else if(nType == keGroupBoxSkin)
        {
            pObject = new CGroupBoxSkin;
        }
        else if(nType == keStaticSkin)
        {
            pObject = new CStaticSkin;
        }
        else if(nType == keEditSkin)
        {
            pObject = new CEditSkin;
        }
        else if(nType == keComboxSkin)
        {
            pObject = new CComboBoxSkin;
        }
        else if(nType == keListBoxSkin)
        {
            pObject = new CListBoxSkin;
        }
        else if(nType == kePopMenuSkin)
        {
            pObject = new CPopupMenuSkin;
        }
        else if(nType == keProgressSkin)
        {
            pObject = new CProgressSkin;
        }
        else if(nType == keSpinSkin)
        {
            pObject = new CSpinSkin;
        }
        else if(nType == keHeaderSkin)
        {
            pObject = new CHeaderSkin;
        }
        else if(nType == keSliderSkin)
        {
            pObject = new CSliderSkin;
        }
        else if(nType == keTabSkin)
        {
            pObject = new CTabSkin;
        }
        else if(nType == keStatusbarSkin)
        {
            pObject = new CStatusBarSkin;
        }
        else if(nType == keToolbarSkin)
        {
            pObject = new CToolBarSkin;
        }
        pObject->SetSkinVersion(m_nSkinVersion);
        pObject->Serialize(ar);

        m_lstSkinObjects.push_back(pObject);
    }

    ar.Close();
}

void CSkin::SaveSkin( const CString&strSkinFile )
{
	CFile			cFile;
	CFileException	e;

	if (cFile.Open(strSkinFile, CFile::modeCreate |
		CFile::modeReadWrite | CFile::shareExclusive, &e))
	{
		CArchive ar(&cFile,CArchive::store);

		// 存储为 最新版本		
		m_nSkinVersion = SKINVERSION;
		ar.Write(&m_nSkinVersion,sizeof(m_nSkinVersion));

		int imageMark = SKIN_IMAGE_MARK;
		ar.Write(&imageMark,sizeof(imageMark));
		if(!m_pImages)
			m_pImages = new CSkinImages;
		m_pImages->Serialize(ar);

		ar.Write(&m_Application,sizeof(m_Application));
		
		int nObjectSkin = m_lstSkinObjects.size();
		ar.Write(&nObjectSkin,sizeof(nObjectSkin));

		for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
			iter != m_lstSkinObjects.end(); ++iter)
		{
			CObjectSkin *pObject = *iter;
			int nType = pObject->GetSkinType();
			ar.Write(&nType,sizeof(nType));
			pObject->Serialize(ar);
		}
	}
}

CSkinBitmap* CSkin::LoadImage( const CString& strImageFile )
{
	return m_pImages->LoadImage(strImageFile);
}
void CSkin::SaveImage( const CString& strImageFile )
{
	
}
CSkinBitmap* CSkin::FindIamge( const CString& strImageFile )
{
	return m_pImages->FindImage(strImageFile);
}

void CSkin::DeleteImage(const CString & strImageFile)
{
	m_pImages->DeleteImage(strImageFile);
}

CWindowSkin* CSkin::GetWindowSkin()
{
    return reinterpret_cast<CWindowSkin*>(GetObjectSkin(keWindowSkin));
}

CScrollBarSkin* CSkin::GetScrollBarSkin()
{
    return reinterpret_cast<CScrollBarSkin*>(GetObjectSkin(keScrollBarSkin));
}

CStaticSkin* CSkin::GetStaticSkin()
{
    return reinterpret_cast<CStaticSkin*>(GetObjectSkin(keStaticSkin));
}


CButtonSkin* CSkin::GetButtonSkin(const char* szSkinName)
{
	CObjectSkin *pObject = NULL;
	for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
		iter != m_lstSkinObjects.end(); ++iter)
	{
		CObjectSkin *pObject = *iter;

		if((pObject->GetSkinType() == keButtonSkin)
			&& (strcmp(pObject->m_strName, szSkinName) == 0))
		{
			return (CButtonSkin*)pObject;
		}
	}
	return NULL;
}

CButtonSkin* CSkin::GetButtonSkin(int nID)
{
	CButtonSkin * pObjectNoID = NULL;
	for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
		iter != m_lstSkinObjects.end(); ++iter)
	{
		CObjectSkin* pObject = *iter;
		if(pObject->GetSkinType() == keButtonSkin)
		{
			bool bMatch;
			if(pObject->FindID(nID, bMatch) != NULL)
			{
				if(bMatch)
				{
					return reinterpret_cast<CButtonSkin*>(pObject);
				}
				else
				{
					pObjectNoID =  reinterpret_cast<CButtonSkin*>(pObject);
				}
			}
		}
	}
	return pObjectNoID;
}

CRadioSkin*	 CSkin::GetRadioSkin()
{
    return reinterpret_cast<CRadioSkin*>(GetObjectSkin(keRadioSkin));
}
CCheckBoxSkin* CSkin::GetCheckBoxSkin()
{
    return reinterpret_cast<CCheckBoxSkin*>(GetObjectSkin(keCheckBoxSkin));
}
CGroupBoxSkin* CSkin::GetGroupBoxSkin()
{
    return reinterpret_cast<CGroupBoxSkin*>(GetObjectSkin(keGroupBoxSkin));
}
CEditSkin* CSkin::GetEditSkin()
{
    return reinterpret_cast<CEditSkin*>(GetObjectSkin(keEditSkin));
}
CComboBoxSkin* CSkin::GetComboxSkin()
{
    return reinterpret_cast<CComboBoxSkin*>(GetObjectSkin(keComboxSkin));
}
CListBoxSkin* CSkin::GetListBoxSkin()
{
    return reinterpret_cast<CListBoxSkin*>(GetObjectSkin(keListBoxSkin));
}
CPopupMenuSkin*	CSkin::GetPopupMenuSkin()
{
    return reinterpret_cast<CPopupMenuSkin*>(GetObjectSkin(kePopMenuSkin));
}
CProgressSkin* CSkin::GetProgressSkin()
{
    return reinterpret_cast<CProgressSkin*>(GetObjectSkin(keProgressSkin));
}
CSpinSkin* CSkin::GetSpinSkin()
{
    return reinterpret_cast<CSpinSkin*>(GetObjectSkin(keSpinSkin));
}
CHeaderSkin* CSkin::GetHeaderSkin()
{
    return reinterpret_cast<CHeaderSkin*>(GetObjectSkin(keHeaderSkin));
}
CSliderSkin* CSkin::GetSliderSkin()
{
    return reinterpret_cast<CSliderSkin*>(GetObjectSkin(keSliderSkin));
}
CTabSkin* CSkin::GetTabSkin()
{
    return reinterpret_cast<CTabSkin*>(GetObjectSkin(keTabSkin));
}
CStatusBarSkin*	CSkin::GetStatusBarSkin()
{
    return reinterpret_cast<CStatusBarSkin*>(GetObjectSkin(keStatusbarSkin));
}
CToolBarSkin* CSkin::GetToolBarSkin()
{
    return reinterpret_cast<CToolBarSkin*>(GetObjectSkin(keToolbarSkin));
}

// 获得一个新的合法的 Skin Name
void CSkin::GetValidSkinName(CString & strSkinName)
{
	static unsigned int nIndex = 1;
	static std::string strOrigin;

	if(nIndex == 1)
	{
//		strOrigin.clear();  // clear() not available in vc6, but same as follow
        strOrigin.erase(strOrigin.begin(), strOrigin.end());
		strOrigin += strSkinName;
	}


	if(FindObjectSkin(strSkinName) != NULL)
	{
		std::ostringstream ss;
		ss << strOrigin << nIndex++ << std::ends;
		strSkinName.Format("%s", ss.str().c_str());
		GetValidSkinName(strSkinName);
	}
	else
	{
		nIndex = 1;
	}
}


CObjectSkin* CSkin::FindObjectSkin(const char* szName, const CObjectSkin* pParent)
{
	CObjectSkin *pObject = NULL;

	if(pParent == NULL)
	{
		for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
			iter != m_lstSkinObjects.end(); ++iter)
		{
			CObjectSkin *pObject = *iter;

			CString strTemp = pObject->GetName();
			if(strcmp(strTemp, szName) == 0)
				return pObject;
		}
	}
	else
	{
		return pParent->FindChild(szName);
	}
	return NULL;
}

void CSkin::DeleteObjectSkin(CObjectSkin* pSkin)
{
	if(pSkin == NULL)
		return;

	CObjectSkin* pParent = pSkin->GetParent();
	if(pParent == NULL)
	{
		list<CObjectSkin*>::iterator iter = 
			find(m_lstSkinObjects.begin(), m_lstSkinObjects.end(), pSkin);
		if(iter != m_lstSkinObjects.end())
			m_lstSkinObjects.erase(iter);

		delete pSkin;
	}
	else
	{
		pParent->DeleteChild(pSkin->GetName());
	}
}

CObjectSkin* CSkin::GetObjectSkin( int SkinType )
{
    CObjectSkin *pObject = NULL;
    for(list<CObjectSkin*>::iterator iter = m_lstSkinObjects.begin();
        iter != m_lstSkinObjects.end(); ++iter)
    {
        pObject = *iter;
        if(pObject->GetSkinType() == SkinType)
            return pObject;
    }
    return NULL;
}
//void CSkin::AddChild(CObjectSkin *pObjectSkin)
//{
//	if(pObjectSkin == NULL)
//		return;
//	pObjectSkin->SetParent(NULL);
//	m_listTemplate.AddTail(pObjectSkin);
//}
//void CSkin::DeleteChild(CString strName)
//{
//	CObjectSkin* pObjectSkin = NULL;
//	POSITION pos = m_listTemplate.GetHeadPosition();
//	while(pos)
//	{
//		pObjectSkin = m_listTemplate.GetNext(pos);
//		if(pObjectSkin->GetName() == strName)
//		{
//			delete pObjectSkin;
//			break;
//		}
//	}
//	m_listTemplate.RemoveAt(pos);
//}
//int	CSkin::GetChildrenCount()
//{
//	return (int)m_listTemplate.GetCount();
//}
//CObjectSkin* CSkin::FindChild(CString strName)
//{
//	CObjectSkin* pObjectSkin = NULL;
//	POSITION pos = m_listTemplate.GetHeadPosition();
//	while(pos)
//	{
//		pObjectSkin = m_listTemplate.GetNext(pos);
//		if(pObjectSkin->GetName() == strName)
//			return pObjectSkin;
//	}
//	return pObjectSkin;
//}
